package com.zaimokuza.cn.config.security;

import com.zaimokuza.cn.entity.auth.Resources;
import com.zaimokuza.cn.entity.auth.Role;
import com.zaimokuza.cn.service.ResourcesService;
import com.zaimokuza.cn.service.RoleService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;

import javax.annotation.Resource;
import java.io.File;
import java.util.*;

/**
 * 动态获取可访问请求地址对应的资源的角色信息
 *
 * @author zaimokuza
 */
@Slf4j
@Component
public class CustomizeFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

    @Resource
    private RoleService roleService;
    @Resource
    private ResourcesService resourcesService;

    /**
     * 通过Ant路径匹配规则进行匹配路径，需要注意：/get?item=1匹配需要为/get**
     */
    private final static AntPathMatcher ANT_PATH_MATCHER = new AntPathMatcher(File.separator);

    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
        // 获取请求地址
        String requestUrl = ((FilterInvocation) object).getRequestUrl();
        // 实例化可访问该地址的角色信息集合
        Set<ConfigAttribute> needRoleSet = new HashSet<>();
        // 查询所有资源信息
        ArrayList<Resources> resourcesList = resourcesService.getResourcesUrlList();
        // 遍历所有资源信息
        for (Resources resources : resourcesList) {
            // 对请求地址和资源地址进行匹配
            if (ANT_PATH_MATCHER.match(resources.getUrl(), requestUrl)) {
                // 匹配上资源后根据资源ID查询所有可以访问该资源的角色信息
                List<Role> roleList = roleService.getRoleListByResourcesId(resources.getId());
                // 将角色信息整理为集合并去重
                for (Role role : roleList) {
                    needRoleSet.add(new SecurityConfig("ROLE_" + role.getName()));
                }
            }
        }
        // 将可访问的角色集合向后传递
        return needRoleSet;
    }

    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }

    @Override
    public boolean supports(Class<?> aClass) {
        return FilterInvocation.class.isAssignableFrom(aClass);
    }

}